/**
 * luacerun.cpp
 *
 *   Execute a single .lua file inside Windows CE.
 *
 *   Pedro M. Rabinovitch, Nov 2002
 **/

#include <windows.h>

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "luaconf.h"
}

lua_State *L = NULL;
static const char *progname = LUA_PROGNAME;

static int incomplete (lua_State *L, int status) {
  if (status == LUA_ERRSYNTAX) {
    size_t lmsg;
    const char *msg = lua_tolstring(L, -1, &lmsg);
    const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
    if (strstr(msg, LUA_QL("<eof>")) == tp) {
      lua_pop(L, 1);
      return 1;
    }
  }
  return 0;  /* else... */
}

static void l_message (const char *pname, const char *msg) {
  if (pname) fprintf(stderr, "%s: ", pname);
  fprintf(stderr, "%s\n", msg);
  fflush(stderr);
}

static int report (lua_State *L, int status) {
  if (status && !lua_isnil(L, -1)) {
    const char *msg = lua_tostring(L, -1);
    if (msg == NULL) msg = "(error object is not a string)";
    l_message(progname, msg);
    lua_pop(L, 1);
  }
  return status;
}
static const char *get_prompt (lua_State *L, int firstline) {
  const char *p;
  lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
  p = lua_tostring(L, -1);
  if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
  lua_pop(L, 1);  /* remove global */
  return p;
}

static int pushline (lua_State *L, int firstline) {
  char buffer[LUA_MAXINPUT];

  char *b = buffer;
  size_t l;
  const char *prmt = get_prompt(L, firstline);
  if (lua_readline(L, b, prmt) == 0)
    return 0;  /* no input */
  l = strlen(b);
  if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */
    b[l-1] = '\0';  /* remove it */
  if (firstline && b[0] == '=')  /* first line starts with `=' ? */
    lua_pushfstring(L, "return %s", b+1);  /* change it to `return' */
  else
    lua_pushstring(L, b);
  lua_freeline(L, b);
  return 1;
}

static int loadline (lua_State *L) {
  int status;
  lua_settop(L, 0);
  if (!pushline(L, 1))
    return -1;  /* no input */
  for (;;) {  /* repeat until gets a complete line */
    status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
    if (!incomplete(L, status)) break;  /* cannot try to add lines? */
    if (!pushline(L, 0))  /* no more input? */
      return -1;
    lua_pushliteral(L, "\n");  /* add a new line... */
    lua_insert(L, -2);  /* ...between the two lines */
    lua_concat(L, 3);  /* join them */
  }
  lua_saveline(L, 1);
  lua_remove(L, 1);  /* remove line */
  return status;
}
static int traceback (lua_State *L) {
  lua_getfield(L, LUA_GLOBALSINDEX, "debug");
  if (!lua_istable(L, -1)) {
    lua_pop(L, 1);
    return 1;
  }
  lua_getfield(L, -1, "traceback");
  if (!lua_isfunction(L, -1)) {
    lua_pop(L, 2);
    return 1;
  }
  lua_pushvalue(L, 1);  /* pass error message */
  lua_pushinteger(L, 2);  /* skip this function and traceback */
  lua_call(L, 2, 1);  /* call debug.traceback */
  return 1;
}

static int docall (lua_State *L, int narg, int clear) {
  int status;
  int base = lua_gettop(L) - narg;  /* function index */
  lua_pushcfunction(L, traceback);  /* push traceback function */
  lua_insert(L, base);  /* put it under chunk and args */
  //signal(SIGINT, laction); -- Unavaiable for WinCE. It's designed to echo to Ctrl+C originally
  status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
  //signal(SIGINT, SIG_DFL);
  lua_remove(L, base);  /* remove traceback function */
  /* force a complete garbage collection in case of errors */
  if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
  return status;
}

static void dotty (lua_State *L) {
  int status;
  const char *oldprogname = progname;
  progname = NULL;
  while ((status = loadline(L)) != -1) {
    if (status == 0) status = docall(L, 0, 0);
    report(L, status);
    if (status == 0 && lua_gettop(L) > 0) {  /* any result to print? */
      lua_getglobal(L, "print");
      lua_insert(L, 1);
      if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
        l_message(progname, lua_pushfstring(L,
                               "error calling " LUA_QL("print") " (%s)",
                               lua_tostring(L, -1)));
    }
  }
  lua_settop(L, 0);  /* clear stack */
  fputs("\n", stdout);
  fflush(stdout);
  progname = oldprogname;
}

//search the file
//1. absolute path
//2. Current directory
//3. Windows direcotory
//4. other predefine directory, for example, /storage card/scripts/
static bool fileExists(const char* filename)
{
	FILE* f = fopen(filename,"r");
	if(f != NULL)
	{
		fclose(f);		
		return true;
	}
	return false;
}
static char* findFile(const char* filename)
{
#ifdef UNDER_CE
	char* fullpath = new char[MAX_PATH];

	if(filename != NULL && strlen(filename) > 0)
	{
		if(filename[0] == '\\')//absolute path
		{
			if(fileExists(filename))
			{
				strcpy(fullpath,filename);
				return fullpath;
			}		
		}
		else
		{
			TCHAR tpath[MAX_PATH];
			memset(tpath,0,MAX_PATH*sizeof(TCHAR));
			GetModuleFileName(NULL,tpath,MAX_PATH-1);
			wcstombs(fullpath,tpath,MAX_PATH);
			char* lastDash = strrchr(fullpath,'\\');			
			fullpath[lastDash-fullpath+1] = 0;
			strcat(fullpath,filename);
			if(fileExists(fullpath))
			{
				return fullpath;
			}
			
			//windows directory
			strcpy(fullpath,"\\windows\\");
			strcat(fullpath,filename);
			if(fileExists(fullpath))
			{
				return fullpath;
			}			
			strcpy(fullpath,"\\storage card\\scripts");
			strcat(fullpath,filename);
			if(fileExists(fullpath))
			{
				return fullpath;
			}									
#endif	
		}
	}
	delete fullpath;
	fullpath = NULL;
	return NULL;
}



int WINAPI WinMain(	HINSTANCE hInstance,
					HINSTANCE hPrevInstance,
					LPTSTR    lpCmdLine,
					int       nCmdShow)
{
	(void)hInstance;
	(void)hPrevInstance;
	(void)lpCmdLine;
	(void)nCmdShow;

	L = lua_open();
	luaL_openlibs(L);

	int iLen = wcslen(lpCmdLine);
	char* lpmbCmdLine = NULL;
	if(iLen > 0)
	{
		lpmbCmdLine = new char[iLen*2+1];
		memset(lpmbCmdLine,0,iLen*2+1);
		wcstombs(lpmbCmdLine,lpCmdLine,iLen*2);
	}

	if(lpmbCmdLine)
	{		
		char* filePath = findFile(lpmbCmdLine);
		if(NULL != filePath)
		{
			int error = luaL_loadfile( L, filePath );
			if(!error)
			{
				error = lua_pcall(L, 0, LUA_MULTRET, 0);
				if(error)
				{
					//error
					report(L,error);
				}
			}
			delete filePath;

		}
		else
		{
			printf("File %s does not exist!\n",lpmbCmdLine);
		}
		delete lpmbCmdLine;
		
	}
	else
	{
		printf("Lua 5.1 for Sunrise ST1100\n");
		dotty(L);
	}

	//this bug is fixed. The reason is that I link the same static lua lib 
	//into both lua51.exe and testext.dll
	//now, I use the dynamic luacedll.dll.
	lua_close(L);

	return 0;
}